package com.jzo2o.foundations.service.impl;

import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.common.utils.StringUtils;
import com.jzo2o.es.core.ElasticSearchTemplate;
import com.jzo2o.es.utils.SearchResponseUtils;
import com.jzo2o.foundations.constants.IndexConstants;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.ServeMapper;
import com.jzo2o.foundations.mapper.ServeTypeMapper;
import com.jzo2o.foundations.model.domain.*;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import com.jzo2o.foundations.service.HomeService;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeItemService;
import com.jzo2o.foundations.service.IServeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 首页查询相关功能
 *
 * @author itcast
 * @create 2023/8/21 10:57
 **/
@Slf4j
@Service
public class HomeServiceImpl implements HomeService {

    @Resource
    private IRegionService regionService;
    @Resource
    private ServeMapper serveMapper;
    @Resource
    private ServeTypeMapper serveTypeMapper;
    @Resource
    private IServeItemService serveItemService;
    @Resource
    private IServeService serveService;
    @Resource
    private ElasticSearchTemplate elasticSearchTemplate;
    /**
     * 根据区域id查询已开通的服务类型
     *
     * @param regionId 区域id
     * @return 已开通的服务类型
     */
    @Override
    @Caching(
            cacheable = {
                    //result为null时,属于缓存穿透情况，缓存时间30分钟
                    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId", unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
                    //result不为null时,永久缓存
                    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId", unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
            }
    )
    public List<ServeCategoryResDTO> queryServeIconCategoryByRegionIdCache(Long regionId) {
        //1.校验当前城市是否为启用状态
        Region region = regionService.getById(regionId);
        if (ObjectUtil.isEmpty(region) || ObjectUtil.equal(FoundationStatusEnum.DISABLE.getStatus(), region.getActiveStatus())) {
            return Collections.emptyList();
        }

        //2.根据城市编码查询所有的服务图标
        List<ServeCategoryResDTO> list = serveMapper.findServeIconCategoryByRegionId(regionId);
        if (ObjectUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        //3.服务类型取前两个，每个类型下服务项取前4个
        //list的截止下标
        int endIndex = Math.min(list.size(), 2);
        List<ServeCategoryResDTO> serveCategoryResDTOS = new ArrayList<>(list.subList(0, endIndex));
        serveCategoryResDTOS.forEach(v -> {
            List<ServeSimpleResDTO> serveResDTOList = v.getServeResDTOList();
            //serveResDTOList的截止下标
            int endIndex2 = Math.min(serveResDTOList.size(), 4);
            List<ServeSimpleResDTO> serveSimpleResDTOS = new ArrayList<>(serveResDTOList.subList(0, endIndex2));
            v.setServeResDTOList(serveSimpleResDTOS);
        });
        return serveCategoryResDTOS;
    }

    @Caching(
            cacheable = {
                    //result为null时,属于缓存穿透情况，缓存时间30分钟
                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
                    //result不为null时,永久缓存
                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
            }
    )
    @Override
    public List<ServeAggregationTypeSimpleResDTO> queryServeTypeList(Long regionId) {
        //1.校验当前城市是否为启用状态
        Region region = regionService.getById(regionId);
        if (ObjectUtil.isEmpty(region) || ObjectUtil.equal(FoundationStatusEnum.DISABLE.getStatus(), region.getActiveStatus())) {
            return Collections.emptyList();
        }
        //2.根据城市编码查询所有的服务类型
        return serveTypeMapper.queryServeTypeList(regionId);
    }

    /**
     * 根据区域id查询热门服务
     *
     * @param regionId 区域id
     * @return 热门服务
     */
    @Caching(
            cacheable = {
                    //result为null时,属于缓存穿透情况，缓存时间30分钟
                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
                    //result不为null时,永久缓存
                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
            }
    )
    @Override
    public List<ServeAggregationSimpleResDTO> hotServeList(Long regionId) {
        //1.校验当前城市是否为启用状态
        Region region = regionService.getById(regionId);
        if (ObjectUtil.isEmpty(region) || ObjectUtil.equal(FoundationStatusEnum.DISABLE.getStatus(), region.getActiveStatus())) {
            return Collections.emptyList();
        }
        //2.根据城市编码查询所有热门服务
        return serveMapper.hotServeList(regionId);
    }

    /**
     * 服务详情
     *
     * @param id 服务id
     * @return 服务详情
     */
    @Override
    public ServeAggregationSimpleResDTO serveDetail(Long id) {
        if (ObjectUtils.isEmpty(id)){
            throw new ForbiddenOperationException("服务id不能为空");
        }
        //查询服务项
        ServeItem serveItem = serveItemService.queryServeItemByServeId(id);
        //查询服务
        Serve serve = serveService.queryByIdAndCache(id);
        //组装数据
        ServeAggregationSimpleResDTO serveAggregationSimpleResDTO = ServeAggregationSimpleResDTO.builder()
                .id(serve.getId())
                .serveItemId(serveItem.getId())
                .serveItemName(serveItem.getName())
                .serveItemImg(serveItem.getImg())
                .unit(serveItem.getUnit())
                .price(serve.getPrice())
                .detailImg(serveItem.getDetailImg())
                .cityCode(serve.getCityCode())
                .build();
        return serveAggregationSimpleResDTO;
    }

    /**
     * 查询服务列表
     *
     * @param cityCode  城市编码
     * @param serveTypeId 服务类型id
     * @param keyword 关键字
     * @return 服务列表
     */
    @Override
    public List<ServeSimpleResDTO> findServeList(String cityCode, Long serveTypeId, String keyword) {
        //构建搜索条件
        SearchRequest request = new SearchRequest.Builder()
                .index(IndexConstants.SERVE)
                .query(q -> q
                        .bool(b -> {
                            b.must(m -> m
                                            .term(t -> t
                                                    .field("city_code")
                                                    .value(cityCode)
                                            )
                                    );
                            if (ObjectUtils.isNotNull(serveTypeId)){
                                b.must(m -> m.term(t -> t.field("serve_type_id").value(serveTypeId)));
                            }
                            if (StringUtils.isNotBlank(keyword)){
                                b.must(m -> m.match(t -> t.field("serve_item_name").query(keyword)));
                            }
                            return b;
                        })
                ).build();
        //执行搜索
        SearchResponse<ServeSync> response = elasticSearchTemplate.opsForDoc().search(request, ServeSync.class);
        if (SearchResponseUtils.isNotSuccess(response)){
            return Collections.emptyList();
        }
        List<ServeSync> serveSyncList = SearchResponseUtils.getResponse(response);
        log.info("查询服务列表结果：{}", serveSyncList);
        return serveSyncList.stream().map(e -> ServeSimpleResDTO.builder()
                .id(e.getId())
                .serveItemId(e.getServeItemId())
                .serveItemName(e.getServeItemName())
                .serveItemIcon(e.getServeItemIcon())
                .serveItemSortNum(e.getServeItemSortNum())
                .build()).collect(Collectors.toList());
    }
}
